#ifndef __WORLD_H__
#define __WORLD_H__

#include <QString>

#include "ngl/Camera.h"
#include "ngl/Colour.h"
#include "ngl/SpotLight.h"
#include "ngl/TransformStack.h"
#include "ngl/Obj.h"
#include "ngl/BBox.h"

#include "ShaderManager.h"
#include "Cloth.h"
#include "ObstacleManager.h"

#include <QtOpenGL>

/// @file SimulationManager.h
/// @brief represents the gl context and the main simulation of our application
/// @author Perseedoss Rajiv
/// @version 1.0
/// @date 12.04.11
/// Revision History :
/// Initial Version 12.04.11
/// @class SimulationManager
/// @brief the main simulation class that creates all other objects of the simulation, it also
/// is the main opengl context and allows drawing functionalities

class SimulationManager : public QGLWidget
{
Q_OBJECT

public:
    /// @brief ctor
    /// @param [in] _parent the parent window to create the GL context in
    SimulationManager(
            QWidget* _parent
        );

    /// @brief dtor
    ~SimulationManager();

    /// @brief handle keypress events
    /// @param[in] _event the Qt Event structure, holding information about keypresses
    void keyPress(QKeyEvent* _event);

    /// @brief returns the cloth object of the simulation
    inline Cloth* getCloth() const { return  m_cloth; }

    /// @brief returns the obstacle manager object
    inline ObstacleManager* getObstacleManager() const { return  m_obstacleManager; }

    /// @brief this method is used to setup the 2D top view
    void setup2DTopView();

    /// @brief this method is used to setup the 2D front view
    void setup2DFrontView();


public slots:
    /// @brief called when the camera zoom slider value is changed in the GUI; it slides the camera along its N vector
    /// @param[in] _depth the zoom factor to set to the camera
    void updateCameraZoom(const int _depth);


protected:
    /// @brief called when the window context is created
    void initializeGL();

    /// @brief called whenever the window is re-sized
    /// @param[in] _w the width of the resized window
    /// @param[in] _h the height of the resized window
    void resizeGL
                (
                    const int _w,
                    const int _h
                );

    /// @brief main gl drawing method that is called whenever the window needs to be re-drawn
    void paintGL();


private :
    /// @brief the x rotation mouse value
    int m_spinXFace;

    /// @brief the y rotation mouse value
    int m_spinYFace;

    /// @brief flag to indicate if the mouse button is pressed when dragging
    bool m_rotate;

    /// @brief the previous x mouse value
    int m_origX;

    /// @brief the previous y mouse value
    int m_origY;

    /// @brief right mouse camera movement x value
    int m_moveX;

    /// @brief right mouse camera movement y value
    int m_moveY;

    /// @brief flag to indicate if the right mouse is pressed for (x,y) mouse movement
    bool m_move;

    /// @brief starting x position of the right mouse
    int m_origMoveX;

    /// @brief starting y position of the right mouse
    int m_origMoveY;

    /// @brief toggle help flag
    bool m_drawHelp;

    /// @brief aspect ratio of the camera
    float m_aspect;

    /// @brief mouse move sensitivity
    int m_mouseMoveSensitivity;

    /// @brief frame update rate
    int m_frameRate;

    /// @brief global transform stack
    ngl::TransformStack m_transformStack;

    /// @brief ngl light object
    ngl::Light m_light;

    /// @brief ngl camera object
    ngl::Camera m_camera;

    /// @brief shader manager
    ShaderManager* m_shaderManager;

    /// @brief obstacle manager
    ObstacleManager* m_obstacleManager;

    /// @brief cloth manager
    Cloth* m_cloth;

    /// @brief main timer
    int m_timer;

    /// @brief the last depth of a camera zoom operation
    float m_lastCamZ;


private :
    /// @brief the timer event triggered from the timers
    void timerEvent(QTimerEvent* _event);

    /// @brief this method create our camera
    void createCamera();

    /// @brief this method create our light
    void createLight();

    /// @brief this method display the text help overlay on the screen
    void displayHelp();

    /// @brief this method is called every time a mouse is moved
    /// @param[in] _event the Qt Event structure
    void mouseMoveEvent(
                            QMouseEvent* _event
                        );

    /// @brief this method is called everytime the mouse button is pressed
    /// @param _event the Qt Event structure
    void mousePressEvent(
                            QMouseEvent* _event
                        );

    /// @brief this method is called everytime the mouse button is released
    /// @param _event the Qt Event structure
    void mouseReleaseEvent(
                            QMouseEvent* _event
                            );

    /// @brief this method is called to initialise all the objects/params of the simulation
    void initialiseSimulation();

    /// @brief this method is called to delete all the objects/managers of the world
    void deleteSimulationObjects();


};
#endif // __WORLD_H__
